package com.ygqh.baby.service.impl;

import com.foxinmy.weixin4j.util.StringUtil;
import com.ygqh.baby.ao.*;
import com.ygqh.baby.exception.YgException;
import com.ygqh.baby.mapper.YgDrawPrizeMapper;
import com.ygqh.baby.model.*;
import com.ygqh.baby.model.PrizeItem.Type;
import com.ygqh.baby.po.*;
import com.ygqh.baby.po.YgDrawPrizeExample.Criteria;
import com.ygqh.baby.redis.RedisDao;
import com.ygqh.baby.service.*;
import com.ygqh.baby.utils.DateConvertUtils;
import com.ygqh.baby.utils.DrawPrizeUtil;
import com.ygqh.baby.utils.SplitPriceUtil;
import com.ygqh.baby.utils.ThreadPool;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;

@Service
public class YgDrawPrizeServiceImpl implements YgDrawPrizeService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private YgDrawPrizeMapper ygDrawPrizeMapper;
    @Autowired
    private RedisDao redisDao;
    @Autowired
    private YgUserBalanceService ygUserBalanceService;
    @Autowired
    private YgCouponService ygCouponService;
    @Autowired
    private YgDrawPrizeRecordService ygDrawPrizeRecordService;
    @Autowired
    private YgUserPrizeService ygUserPrizeService;
    @Autowired
    private YgCouponDetailService ygCouponDetailService;
    @Autowired
    private ThreadPool threadPool;
    @Autowired
    private YgDrawPrizeHelpService ygDrawPrizeHelpService;
    @Autowired
    private YgUserService ygUserService;
    @Autowired
    private YgUserBalanceDetailService ygUserBalanceDetailService;
    @Autowired
    private YgCardCouponDetailService ygCardCouponDetailService;

    @Override
    public List<YgDrawPrize> find() {
        YgDrawPrizeExample example = new YgDrawPrizeExample();
        example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        return ygDrawPrizeMapper.selectByExample(example);
    }

    @Override
    public int findCount() {
        YgDrawPrizeExample example = new YgDrawPrizeExample();
        example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        return ygDrawPrizeMapper.countByExample(example);
    }

    @Override
    public YgDrawPrize findById(Long id) {
        return ygDrawPrizeMapper.selectByPrimaryKey(id);
    }

    @Override
    public int save(YgDrawPrize ygDrawPrize) {
        return ygDrawPrizeMapper.insertSelective(ygDrawPrize);
    }

    @Override
    public int update(YgDrawPrize ygDrawPrize) {
        return ygDrawPrizeMapper.updateByPrimaryKeySelective(ygDrawPrize);
    }

    @Override
    public ResultSet<YgDrawPrize> search(QueryInfo queryInfo, String q) {
        List<YgDrawPrize> list = ygDrawPrizeMapper.selectSuper(queryInfo, q);
        int count = ygDrawPrizeMapper.countSuper(q);
        ResultSet<YgDrawPrize> resultSet = new ResultSet<YgDrawPrize>(count, list);
        return resultSet;
    }

    @Override
    public int deleteSoft(Long[] ids) {
        Assert.notEmpty(ids);
        YgDrawPrizeExample example = new YgDrawPrizeExample();
        example.createCriteria().andIdIn(Arrays.asList(ids));
        YgDrawPrize record = new YgDrawPrize();
        record.setStatus(DataStatus.Delete);

        return ygDrawPrizeMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int deleteSoft(Long id) {
        return this.deleteSoft(new Long[]{id});
    }

    @Override
    public int saveOrUpdate(YgDrawPrize ygDrawPrize) {
        int r = 0;
        if (ygDrawPrize.getId() != null) {
            r = this.update(ygDrawPrize);
        } else {
            r = this.save(ygDrawPrize);
        }
        return r;
    }

    @Override
    public PrizeItem drawPrize(DrawPrize drawPrize, YgUser user) {
        int selectId = DrawPrizeUtil.lottery(drawPrize.getRates());
        PrizeItem prizeItem = givePrize(drawPrize, user, selectId);
        return prizeItem;
    }

    private PrizeItem givePrize(DrawPrize drawPrize, YgUser user, Integer selectId) {
        LinkedList<PrizeItem> prizeItems = drawPrize.getPrizeItems();
        PrizeItem prizeItem = prizeItems.get(selectId);
        Integer defaultIndex = drawPrize.getDefaultIndex();

        String baseKey = drawPrize.getBaseKey(false);

        String itemKey = prizeItem.getKey(baseKey);
        int count = getPrizeGiveCount(itemKey);
        if (prizeItem.isLimit()) {

            if (count >= prizeItem.getLimitCount()) {
                prizeItem = this.getDefaultItem(prizeItems, defaultIndex);
            } else {
                count++;
                redisDao.set(itemKey, count + "", 24 * 60 * 60 * 1000);
            }
        }

        prizeItem.setFalg(drawPrize.getFalg());
        doGivePrizeBussness(prizeItem, user, drawPrize.getSourceCode(), baseKey);

        return prizeItem;

    }

    private void doGivePrizeBussness(PrizeItem prizeItem, YgUser user, String sourceCode, String baseKey) {
        String relationCode = prizeItem.getRelationCode();
        Type type = prizeItem.getType();
        if (type.equals(Type.Balance)) {
            ygUserBalanceService.incomeRecharge(user.getId(), new BigDecimal(relationCode), OperationType.Activity, "抽奖", baseKey, null);

        } else if (type.equals(Type.Coupon)) {
            // 优惠券
            ygCouponService.receiveCoupon(Long.parseLong(relationCode), user);

        } else if (type.equals(Type.Goods)) {
            this.getThisDrawPrizeRate(prizeItem, user, baseKey);

        }
        ygDrawPrizeRecordService.addRecord(prizeItem, user, sourceCode);
        this.updateCount(user.getId(), -1, sourceCode, prizeItem.getContent(), prizeItem.getKey(baseKey));
        ygUserPrizeService.writeBackCount(prizeItem, user.getId(), sourceCode);

    }

    private PrizeItem getThisDrawPrizeRate(PrizeItem prizeItem, YgUser user, String baseKey) {
        if (prizeItem.getType().equals(Type.Goods)) {
            int count = ygDrawPrizeRecordService.countByUserId(user.getId(), prizeItem.getType(), baseKey);
            BigDecimal totalRate = ygDrawPrizeRecordService.getTotalRateByUserId(user.getId(), prizeItem.getType(), baseKey);
            if (prizeItem.getFalg() != null && prizeItem.getFalg()) {
                getThisDrawPrizeRate$One(prizeItem, count, totalRate);
//				getThisDrawPrizeRate$CatchWaWa(prizeItem, count + 1, totalRate);
            } else {
                prizeItem.setThisRate(BigDecimal.ONE);
                prizeItem.setTotalRate(BigDecimal.ONE);
            }
        }

        return prizeItem;

    }

    private void getThisDrawPrizeRate$CatchWaWa(PrizeItem prizeItem, int count, BigDecimal totalRate) {
        Integer gradeTimes = PrizeItemCatchWaWa.getGradeTimes(count);
        Boolean falg = PrizeItemCatchWaWa.getPrize(gradeTimes, count, totalRate);
        if (falg) {
            prizeItem.setThisRate(new BigDecimal("0.20"));
        } else {
            prizeItem.setThisRate(new BigDecimal("0.00"));

        }
        prizeItem.setTotalRate(totalRate.add(prizeItem.getThisRate()));
    }

    private PrizeItem getThisDrawPrizeRate$One(PrizeItem prizeItem, int count, BigDecimal totalRate) {
        if (count < 3) {
            BigDecimal r = getRandomRate(0.62F, 0.86F).subtract(totalRate);
            Float rate = SplitPriceUtil.splitPriceD(r.floatValue(), 3 - count);
            BigDecimal thisRate = new BigDecimal(rate).setScale(2, BigDecimal.ROUND_HALF_UP);
            prizeItem.setThisRate(thisRate);
            prizeItem.setTotalRate(totalRate.add(thisRate));

            // if (count == 2) {
            // extraReward(prizeItem, user);
            //
            // }

            return prizeItem;
        }
        int lastDrawCount = prizeItem.getDrawCount() - count;

        if (lastDrawCount > 0) {
            BigDecimal r = new BigDecimal("1").subtract(totalRate);
            Float rate = SplitPriceUtil.splitPriceD(r.floatValue(), prizeItem.getDrawCount() - count);
            BigDecimal thisRate = new BigDecimal(rate).setScale(2, BigDecimal.ROUND_HALF_UP);
            prizeItem.setThisRate(thisRate);
            prizeItem.setTotalRate(totalRate.add(thisRate));
        } else {
            throw new YgException("-1", "亲爱的麻麻，您已经可以兑换啦！");
        }
        return prizeItem;
    }

    private BigDecimal getRandomRate(float min, float max) {
        return BigDecimal.valueOf(Math.random() * (max - min) + min).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    private void extraReward(PrizeItem prizeItem, YgUser user) {

        String content = "";
        Double[] orignalRates = new Double[]{0.18, 0.02, 0.8};
        int lottery = DrawPrizeUtil.lottery(Arrays.asList(orignalRates));
        if (lottery == 2) {
            Long couponId = 246L;
            giveCouponByRate(couponId, user);
            YgCoupon coupon = ygCouponService.findById(couponId);
            content = coupon.getCouponTitle();
        } else {
            int money = lottery == 0 ? 1 : 5;
            BigDecimal decimal = new BigDecimal(money);
            ygUserBalanceService.backAcountPrice(user.getId(), decimal);
            ygUserBalanceDetailService.addBalanceDetail(user.getId(), decimal, BalanceType.Balance, OperationType.Activity, "扭一扭礼包");

            content = money + "元成长基金";
        }
        prizeItem.setCoupon(content);

    }

    private void giveCouponByRate(Long couponId, YgUser user) {
        threadPool.getExecutorService().execute(new Runnable() {

            @Override
            public void run() {
                ygCouponDetailService.receiveCoupon(couponId, DateConvertUtils.getMonthEndDate(new Date()), user);

            }
        });

    }

    private PrizeItemRule getPrizeItemRule(PrizeItem prizeItem, int count) {
        PrizeItemRule itemRule = null;
        List<PrizeItemRule> list = prizeItem.getRuleList();

        if (!CollectionUtils.isEmpty(list)) {

            for (PrizeItemRule rule : list) {
                if (rule.inThisRule(count)) {
                    itemRule = rule;
                    break;

                }
            }
        }
        return itemRule;

    }

    private PrizeItem getDefaultItem(List<PrizeItem> prizeItems, Integer index) {
        PrizeItem defalutItem = null;
        for (PrizeItem prizeItem : prizeItems) {
            if (prizeItem.getIndex().equals(index)) {
                defalutItem = prizeItem;
            }
        }
        return defalutItem;
    }

    private int getPrizeGiveCount(String key) {
        String countStr = redisDao.get(key);
        return StringUtil.isEmpty(countStr) ? 0 : Integer.parseInt(countStr);

    }

    @Override
    public int findLastCountByUserId(Long userId, String sourceCode) {
        YgDrawPrize drawPrize = this.findByUserId(userId, sourceCode);
        if (drawPrize == null) {
            int count = 3;
            YgUser user = ygUserService.findById(userId);
            if (StringUtils.isNotBlank(user.getOpenId())) {
                Boolean hasHelp = ygDrawPrizeHelpService.hasHelpByOpenId(user.getOpenId(), sourceCode, DataStatus.Valid);
                if (hasHelp) {
                    count = 5;
                }
            }
            drawPrize = new YgDrawPrize();
            drawPrize.setUserId(userId);
            drawPrize.setCount(count);
            drawPrize.setCreateTime(new Date());
            drawPrize.setSourceCode(sourceCode);
            this.save(drawPrize);
        }
        return drawPrize.getCount();
    }

    @Override
    public YgDrawPrize findByUserId(Long userId, String sourceCode) {
        YgDrawPrizeExample example = new YgDrawPrizeExample();
        Criteria criteria = example.createCriteria().andUserIdEqualTo(userId).andStatusEqualTo(DataStatus.Valid.name());
        if (StringUtils.isNotBlank(sourceCode)) {
            criteria.andSourceCodeEqualTo(sourceCode);
        }
        List<YgDrawPrize> list = ygDrawPrizeMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public int addCountByHelp(int count, String sourceCode, Long userId, String openId) {

        return this.updateCount(userId, count, sourceCode, openId, "wxHelp");
    }

    private int updateCount(Long userId, int count, String sourceCode, String remark, String updateBy) {
        return ygDrawPrizeMapper.updateCount(userId, count, sourceCode, remark, updateBy);
    }

    @Override
    public PrizeItem drawPrizeByRate(DrawPrize drawPrize, YgUser user) {
        String sourceCode = drawPrize.getSourceCode();
        YgDrawPrize prize = this.findByUserId(user.getId(), sourceCode);
        if (prize.getRate().compareTo(new BigDecimal("0.00")) == 0) {
            PrizeItem prizeItem = this.drawPrize(drawPrize, user);
            this.updateRate(user.getId(), drawPrize.getSourceCode(), prizeItem.getRate());
            return prizeItem;
        } else {
            LinkedList<PrizeItem> items = drawPrize.getPrizeItems();
            for (PrizeItem item : items) {
                if (item.getRate().compareTo(prize.getRate()) == 0) {
                    item.setFalg(drawPrize.getFalg());
                    try {
                        this.doGivePrizeBussness(item, user, sourceCode, drawPrize.getBaseKey(false));
                    } catch (Exception e) {
                        if (e instanceof YgException) {
                            String errorCode = ((YgException) e).getErrorCode();
                            // 已集满，可以兑换
                            if (StringUtils.isNotBlank(errorCode) && "-1".equals(errorCode)) {
                                item.setTotalRate(BigDecimal.ONE);
                                item.setThisRate(BigDecimal.ZERO);
                            }
                        }
                    }
                    return item;
                }
            }
        }
        return null;
    }

    private int updateRate(Long userId, String sourceCode, BigDecimal rate) {
        YgDrawPrizeExample example = new YgDrawPrizeExample();
        example.createCriteria().andUserIdEqualTo(userId).andSourceCodeEqualTo(sourceCode).andStatusEqualTo(DataStatus.Valid.name());
        YgDrawPrize record = new YgDrawPrize();
        record.setRate(rate);
        return ygDrawPrizeMapper.updateByExampleSelective(record, example);

    }

    @Override
    public List<FriendsRankings> getFriendsRankings(Long userId, String openId, String source) {
        List<FriendsRankings> list = ygDrawPrizeMapper.getFriendsRankings(userId, openId, source);
        Collections.sort(list, new Comparator<FriendsRankings>() {

            @Override
            public int compare(FriendsRankings o1, FriendsRankings o2) {
                int count1 = o1.getCatchCount();
                int count2 = o2.getCatchCount();
                if (count1 - count2 > 0) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });

        int row = 1;
        for (int i = 0; i < list.size(); i++) {
            FriendsRankings item = list.get(i);
            if (i > 0) {
                FriendsRankings previous = list.get(i - 1);
                if (previous.getCatchCount() == item.getCatchCount()) {
                    item.setRanking(row);
                } else {
                    item.setRanking(++row);
                }
            } else {
                // 第一个元素
                item.setRanking(row);
            }

        }
        return list;
    }

    @Override
    public PrizeItem drawPrizeV3(DrawPrize drawPrize, YgUser user, String platformNo) {
        PrizeItem prizeItem = generateDrawPrizeV3(drawPrize, user.getId(), platformNo);
        String baseKey = drawPrize.getBaseKey(false, platformNo);
        logger.info("【抽奖活动】抽中的奖品，userId={}, prizeItem={}", user.getId(), prizeItem);
        Message message = processPrizeItem(prizeItem, user, drawPrize.getActivityName(), baseKey);
        if (!Message.isSuccess(message)) {
            logger.error("【抽奖活动】处理奖品异常，errMsg={}，userId={}, prizeItem={}",
                    message.getContent(), user.getId(), prizeItem);
            // 处理奖品异常，给默认奖品
            prizeItem = this.getDefaultItem(drawPrize.getPrizeItems(), drawPrize.getDefaultIndex());
            message = processPrizeItem(prizeItem, user, drawPrize.getActivityName(), baseKey);
            if (!Message.isSuccess(message)) {
                logger.error("【抽奖活动】处理默认奖品异常，errMsg={}，userId={}, prizeItem={}",
                        message.getContent(), user.getId(), prizeItem);
                return null;
            }
        }
        ygDrawPrizeRecordService.addRecord(prizeItem, user, baseKey);
        ygUserPrizeService.writeBackCount(prizeItem, user.getId(), baseKey);
        return prizeItem;
    }

    private Message processPrizeItem(PrizeItem prizeItem, YgUser user, String activityName, String baseKey) {
        Type type = prizeItem.getType();
        Message message = null;
        if (type.equals(PrizeItem.Type.Balance)) {
            message = ygUserBalanceService.incomeRecharge(user.getId(), new BigDecimal(prizeItem.getRelationCode()),
                    OperationType.Activity, activityName, baseKey, null);
        } else if (type.equals(Type.Coupon)) {
            // 优惠券
            String relationCode = prizeItem.getRelationCode();
            for (String s : relationCode.split(",")) {
                if (StringUtils.isBlank(s)) {
                    continue;
                }
                message = ygCouponDetailService.
                        receiveCouponWithRemark(Long.parseLong(s), activityName + "-" + baseKey, user);
                if (!Message.isSuccess(message)) {
                    logger.error("【转盘抽奖】处理优惠券奖品异常 couponId={}，errMsg={}", s, message.getContent());
                    break;
                }
                prizeItem.setRelationCode(s);
            }
            if (message == null) {
                message = Message.error("【转盘抽奖】处理优惠券奖品异常，奖品关联值为空");
            }
        } else if (type.equals(Type.Goods)) {
            try {
                this.getThisDrawPrizeRate(prizeItem, user, baseKey);
                message = Message.success(null);
            } catch (Exception e) {
                logger.error("【转盘抽奖】处理实物奖品异常，" + e.getMessage(), e);
                message = Message.error("处理实物奖品异常", null);
            }
        } else if (type.equals(Type.Card)) {
            message = ygCardCouponDetailService.generateCardCoupon(user.getId(), Long.parseLong(prizeItem.getRelationCode()),
                    null, activityName + "-" + baseKey);
        } else {
            logger.warn("抽中不存在的奖品类型，userId={}, type={}", user.getId(), type);
            message = Message.error("奖品类型不存在", null);
        }
        return message;
    }

    private PrizeItem generateDrawPrizeV3(DrawPrize drawPrize, Long userId, String platformNo) {
        Boolean newCustom = ygUserService.isNewCustom(userId, platformNo);
        int selectId = DrawPrizeUtil.lottery(drawPrize.getRates(newCustom));
        PrizeItem prizeItem = drawPrize.getPrizeItems().get(selectId);
        if (Type.Cash.equals(prizeItem.getType())) {
            prizeItem = this.getDefaultItem(drawPrize.getPrizeItems(), drawPrize.getDefaultIndex());
        }
        return prizeItem;
    }

    private BigDecimal getBalanceValue() {
        Double balanceValue = Math.random() * 0.5;
        BigDecimal decimal = BigDecimal.valueOf(balanceValue).setScale(2, BigDecimal.ROUND_UP);
        if (decimal.compareTo(BigDecimal.valueOf(0)) == 0) {
            decimal = getBalanceValue();
        }
        return decimal;
    }

    @Override
    public YgDrawPrize initDrawPrize(String sourceCode, Long userId, int initCount, int helpCount) {
        int size = ygDrawPrizeHelpService.countByUserId(userId, sourceCode);
        initCount += size * helpCount;
        YgDrawPrize drawPrize = new YgDrawPrize();
        drawPrize.setUserId(userId);
        drawPrize.setSourceCode(sourceCode);
        drawPrize.setCount(initCount);
        drawPrize.setCreateTime(new Date());
        this.save(drawPrize);
        return drawPrize;
    }

    @Override
    public int updateCountById(Integer count, Long id) {
        YgDrawPrize record = new YgDrawPrize();
        record.setId(id);
        record.setCount(count);
        return ygDrawPrizeMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public List<YgDrawPrize> findList(String sourceCode) {

        YgDrawPrizeExample example = new YgDrawPrizeExample();
        example.createCriteria().andSourceCodeEqualTo(sourceCode).andStatusEqualTo(DataStatus.Valid.name());
        return ygDrawPrizeMapper.selectByExample(example);
    }

}
